package reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Author itcast
 * Date 2021/10/13 10:02
 * Desc TODO
 */
public class StudentDemo {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //反射机制，获取类对象的方式有三种
        //1.类名.class
        Class<Student> clazz = Student.class;
        System.out.println(clazz);
        //2.对象.getClass
        Student student = new Student();
        Class<? extends Student> clazz1 = student.getClass();
        System.out.println(clazz1);
        //3.Class.forName(全路径类名);
        Class<?> clazz2 = Class.forName("reflect.Student");
        System.out.println(clazz2);

        //获取当前 Student 类有哪些构造方法
        Constructor<?>[] cs = clazz.getConstructors();
        for (Constructor<?> c : cs) {
            System.out.println(c);
        }
        //实例化 student 这个类通过反射机制
        //等价于  new Student()
        Student s = clazz.newInstance();
        System.out.println(s);
        //实例化 student 带参的构造器
        Constructor<Student> c2 = clazz.getConstructor(String.class, int.class);
        //等价于 new Student("zhangsan",20)
        Student zs = c2.newInstance("zhangsan", 20);
        System.out.println(zs.toString());

        //获取 student 类中所有的成员变量
        // private String name;
        // private int age;
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        System.out.println("---------------------------");
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        //获取单独的一个变量
        Field name = clazz.getDeclaredField("name");
        //给当前变量赋值
        // 类似于 setName("张三")
        //setAccessible true : public  false : private
        // 将 name 的存取修饰符改为 public
        name.setAccessible(true);
        name.set(zs,"zhubajie");
        System.out.println(zs);

        //获取成员方法
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
        //读取 eat 方法
        // name : 方法名称  Class parameterTypes : 传递的参数
        Method eat = clazz.getDeclaredMethod("eat",String.class,String.class);
        System.out.println(eat);
        //通过反射机制来调用 eat 方法
        //方法名称.invoke(调用的对象名称,可变参数)
        System.out.println("-------------------------------------------------");
        eat.invoke(zs,"猫","fish");
    }
}
